
#include "ili9341_lcd.h"

_lcd_dev lcddev;
/*****************************************************************************
 * @name       :void LCD_WR_REG(uint8_t data)
 * @date       :2018-08-09 
 * @function   :Write an 8-bit command to the LCD screen
 * @parameters :data:Command value to be written
 * @retvalue   :None
******************************************************************************/
void LCD_WR_REG(uint8_t data)
{ 
  	LCD_CS_CLR;     
	LCD_RS_CLR;	  
	SPI_WriteByte(data);
 	LCD_CS_SET;	
}

/*****************************************************************************
 * @name       :void LCD_WR_DATA(uint8_t data)
 * @date       :2018-08-09 
 * @function   :Write an 8-bit data to the LCD screen
 * @parameters :data:data value to be written
 * @retvalue   :None
******************************************************************************/
void LCD_WR_DATA(uint8_t data)
{
    LCD_CS_CLR;
	LCD_RS_SET;
	SPI_WriteByte(data);
	LCD_CS_SET;
}

void LCD_WriteReg(uint8_t LCD_Reg, uint16_t LCD_RegValue)
{	
	LCD_WR_REG(LCD_Reg);  
	LCD_WR_DATA(LCD_RegValue);	    		 
}	   

/*****************************************************************************
 * @name       :void LCD_WriteRAM_Prepare(void)
 * @date       :2018-08-09 
 * @function   :Write GRAM
 * @parameters :None
 * @retvalue   :None
******************************************************************************/	 
void LCD_WriteRAM_Prepare(void)
{
	LCD_WR_REG(lcddev.wramcmd);
}	 

/*****************************************************************************
 * @name       :void Lcd_WriteData_16Bit(uint16_t Data)
 * @date       :2018-08-09 
 * @function   :Write an 16-bit command to the LCD screen
 * @parameters :Data:Data to be written
 * @retvalue   :None
******************************************************************************/	 
void Lcd_WriteData_16Bit(uint16_t Data)
{	
	LCD_CS_CLR;
	LCD_RS_SET;  
	SPI_WriteByte(Data>>8);
	SPI_WriteByte(0x00FF&Data);
	LCD_CS_SET;
}

/*****************************************************************************
 * @name       :void LCD_SetWindows(uint16_t xStar, uint16_t yStar,uint16_t xEnd,uint16_t yEnd)
 * @date       :2018-08-09 
 * @function   :Setting LCD display window
 * @parameters :xStar:the bebinning x coordinate of the LCD display window
								yStar:the bebinning y coordinate of the LCD display window
								xEnd:the endning x coordinate of the LCD display window
								yEnd:the endning y coordinate of the LCD display window
 * @retvalue   :None
******************************************************************************/ 
void LCD_SetWindows(uint16_t xStar, uint16_t yStar,uint16_t xEnd,uint16_t yEnd)
{	
	LCD_WR_REG(lcddev.setxcmd);	
	LCD_WR_DATA(xStar>>8);
	LCD_WR_DATA(0x00FF&xStar);		
	LCD_WR_DATA(xEnd>>8);
	LCD_WR_DATA(0x00FF&xEnd);

	LCD_WR_REG(lcddev.setycmd);	
	LCD_WR_DATA(yStar>>8);
	LCD_WR_DATA(0x00FF&yStar);		
	LCD_WR_DATA(yEnd>>8);
	LCD_WR_DATA(0x00FF&yEnd);

	LCD_WriteRAM_Prepare();			
}   

/*****************************************************************************
 * @name       :void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
 * @date       :2018-08-09 
 * @function   :Set coordinate value
 * @parameters :Xpos:the  x coordinate of the pixel
								Ypos:the  y coordinate of the pixel
 * @retvalue   :None
******************************************************************************/ 
void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
{	  	    			
	LCD_SetWindows(Xpos,Ypos,Xpos,Ypos);	
} 

/*****************************************************************************
 * @name       :void LCD_direction(uint8_t direction)
 * @date       :2018-08-09 
 * @function   :Setting the display direction of LCD screen
 * @parameters :direction:0-0 degree
                          1-90 degree
													2-180 degree
													3-270 degree
 * @retvalue   :None
******************************************************************************/ 
void LCD_direction(uint8_t direction)
{ 
			lcddev.setxcmd=0x2A;
			lcddev.setycmd=0x2B;
			lcddev.wramcmd=0x2C;
	switch(direction){		  
		case 0:						 	 		
			lcddev.width=LCD_W;
			lcddev.height=LCD_H;		
			LCD_WriteReg(0x36,(1<<3)|(0<<6)|(0<<7));//BGR==1,MY==0,MX==0,MV==0
		break;
		case 1:
			lcddev.width=LCD_H;
			lcddev.height=LCD_W;
			LCD_WriteReg(0x36,(1<<3)|(0<<7)|(1<<6)|(1<<5));//BGR==1,MY==1,MX==0,MV==1
		break;
		case 2:						 	 		
			lcddev.width=LCD_W;
			lcddev.height=LCD_H;	
			LCD_WriteReg(0x36,(1<<3)|(1<<6)|(1<<7));//BGR==1,MY==0,MX==0,MV==0
		break;
		case 3:
			lcddev.width=LCD_H;
			lcddev.height=LCD_W;
			LCD_WriteReg(0x36,(1<<3)|(1<<7)|(1<<5));//BGR==1,MY==1,MX==0,MV==1
		break;	
		default:break;
	}		
}	 






void LCD_RESET(void)
{
	LCD_RST_CLR;
	osal_msleep(100);
	LCD_RST_SET;
	osal_msleep(50);
}


static void lcd_gpio_init(void)
{
	uapi_pin_set_mode(LCD_RS, PIN_MODE_0);
    uapi_gpio_set_dir(LCD_RS, GPIO_DIRECTION_OUTPUT);
    uapi_gpio_set_val(LCD_RS, GPIO_LEVEL_LOW);

	uapi_pin_set_mode(LCD_RST, PIN_MODE_0);
    uapi_gpio_set_dir(LCD_RST, GPIO_DIRECTION_OUTPUT);
    uapi_gpio_set_val(LCD_RST, GPIO_LEVEL_LOW);

	uapi_pin_set_mode(LED, PIN_MODE_0);
    uapi_gpio_set_dir(LED, GPIO_DIRECTION_OUTPUT);
    uapi_gpio_set_val(LED, GPIO_LEVEL_LOW);

}


	
void LCD_Init(void)
{  
	osal_printk("LCD_Init start\r\n");

    spi_master_init();
	lcd_gpio_init(); 

    LCD_RST_SET;
    osal_msleep(200);
    LCD_RST_CLR;
    osal_msleep(200);
    LCD_RST_SET;
    osal_msleep(200);


	osal_msleep(500);

	LCD_RESET(); //LCD 复位
//*************3.2inch ILI9341初始化**********//
	LCD_WR_REG(0xCF);  
	LCD_WR_DATA(0x00); 
	LCD_WR_DATA(0xD9); //C1 
	LCD_WR_DATA(0X30); 
	LCD_WR_REG(0xED);  
	LCD_WR_DATA(0x64); 
	LCD_WR_DATA(0x03); 
	LCD_WR_DATA(0X12); 
	LCD_WR_DATA(0X81); 
	LCD_WR_REG(0xE8);  
	LCD_WR_DATA(0x85); 
	LCD_WR_DATA(0x10); 
	LCD_WR_DATA(0x7A); 
	LCD_WR_REG(0xCB);  
	LCD_WR_DATA(0x39); 
	LCD_WR_DATA(0x2C); 
	LCD_WR_DATA(0x00); 
	LCD_WR_DATA(0x34); 
	LCD_WR_DATA(0x02); 
	LCD_WR_REG(0xF7);  
	LCD_WR_DATA(0x20); 
	LCD_WR_REG(0xEA);  
	LCD_WR_DATA(0x00); 
	LCD_WR_DATA(0x00); 
	LCD_WR_REG(0xC0);    //Power control 
	LCD_WR_DATA(0x1B);   //VRH[5:0] 
	LCD_WR_REG(0xC1);    //Power control 
	LCD_WR_DATA(0x12);   //SAP[2:0];BT[3:0] //0x01
	LCD_WR_REG(0xC5);    //VCM control 
	LCD_WR_DATA(0x26); 	 //3F
	LCD_WR_DATA(0x26); 	 //3C
	LCD_WR_REG(0xC7);    //VCM control2 
	LCD_WR_DATA(0XB0); 
	LCD_WR_REG(0x36);    // Memory Access Control 
	LCD_WR_DATA(0x08); 
	LCD_WR_REG(0x3A);   
	LCD_WR_DATA(0x55); 
	LCD_WR_REG(0xB1);   
	LCD_WR_DATA(0x00);   
	LCD_WR_DATA(0x1A); 
	LCD_WR_REG(0xB6);    // Display Function Control 
	LCD_WR_DATA(0x0A); 
	LCD_WR_DATA(0xA2); 
	LCD_WR_REG(0xF2);    // 3Gamma Function Disable 
	LCD_WR_DATA(0x00); 
	LCD_WR_REG(0x26);    //Gamma curve selected 
	LCD_WR_DATA(0x01); 
	LCD_WR_REG(0xE0); //Set Gamma
	LCD_WR_DATA(0x1F);
	LCD_WR_DATA(0x24);
	LCD_WR_DATA(0x24);
	LCD_WR_DATA(0x0D);
	LCD_WR_DATA(0x12);
	LCD_WR_DATA(0x09);
	LCD_WR_DATA(0x52);
	LCD_WR_DATA(0xB7);
	LCD_WR_DATA(0x3F);
	LCD_WR_DATA(0x0C);
	LCD_WR_DATA(0x15);
	LCD_WR_DATA(0x06);
	LCD_WR_DATA(0x0E);
	LCD_WR_DATA(0x08);
	LCD_WR_DATA(0x00);
	LCD_WR_REG(0XE1); //Set Gamma
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x1B);
	LCD_WR_DATA(0x1B);
	LCD_WR_DATA(0x02);
	LCD_WR_DATA(0x0E);
	LCD_WR_DATA(0x06);
	LCD_WR_DATA(0x2E);
	LCD_WR_DATA(0x48);
	LCD_WR_DATA(0x3F);
	LCD_WR_DATA(0x03);
	LCD_WR_DATA(0x0A);
	LCD_WR_DATA(0x09);
	LCD_WR_DATA(0x31);
	LCD_WR_DATA(0x37);
	LCD_WR_DATA(0x1F);

	LCD_WR_REG(0x2B); 
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x01);
	LCD_WR_DATA(0x3f);
	LCD_WR_REG(0x2A); 
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0xef);	 
	LCD_WR_REG(0x11); //Exit Sleep
	osal_msleep(120);// delay_ms(120);
	LCD_WR_REG(0x29); //display on		
	osal_msleep(1200);// delay_ms(120);

  	LCD_direction(USE_HORIZONTAL);//
	LCD_LED_ON;
	
	osal_printk("LCD_Init finish\r\n");
}

/*****************************************************************************
 * @name       :void Lcd_WriteData_16Bit(uint16_t Data)
 * @date       :2018-08-09 
 * @function   :Write an 16-bit command to the LCD screen
 * @parameters :Data:Data to be written
 * @retvalue   :None
******************************************************************************/	


void LCDOutputAFrame(const uint16_t *Frame) {

	LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);
	//osal_msleep(10);
    LCD_CS_CLR;
    LCD_RS_SET;

	uint8_t* Framesub1 =  (uint8_t*)Frame -1;
	SPI_Write320x240x2Bytes(Framesub1);

    LCD_CS_SET;
}


void LCDOutputAFrameU8(uint8_t *Frame) {

	LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);
	//osal_msleep(10);
    LCD_CS_CLR;
    LCD_RS_SET;

	SPI_Write320x240x2Bytes(Frame);

    LCD_CS_SET;
}


static uint8_t g_FrameBuffer[LCD_W*LCD_H*2]={0};//FrameBuffer for write 1 bytes one time

void LCD_Fill(uint16_t color)
{  	
	LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);
	for (int i = 0; i < LCD_W * LCD_H * 2; i=i+2) {
		g_FrameBuffer[i  ] = (color>>8)&0xFF;
		g_FrameBuffer[i+1] = color&0xFF;
	}
	LCDOutputAFrameU8(g_FrameBuffer);
}



/**
 * <---_____y__height_______________
 * | pinVCC                       1 | 
 * |                              2 | 
 * |                              3 | x
 * |                              . | width
 * |                              . | 
 * |                              . | 
 * |______________________________._|
 *///                                                   
void LCD_DisplayImage(uint16_t xstart, uint16_t ystart, Image image)
{  	
	//x:height y:width
	
	if(xstart<0||xstart>=lcddev.height){
		osal_printk("xstart<0||xstart>lcddev.height\r\n");
		return ;
	}else if(ystart<0||ystart>=lcddev.width){
		osal_printk("ystart<0||ystart>lcddev.width\r\n");
		return ;
	}

	LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);

	//120 240
	int diswidth = image.width*2;
	int disheight = image.height;
	
	//LCDW=240,LCDH=320 xstart=240,ystart=220
	if(lcddev.width<(ystart+image.width)){
		osal_printk("image width too large to display all\r\n");
		diswidth=(lcddev.width-ystart)*2;
	}
	if(lcddev.height<(xstart+image.height)){
		osal_printk("image height too large to display all\r\n");
		disheight=lcddev.height-xstart;
	}
	
	osal_printk("diswidth=%d, disheight=%d\r\n", diswidth, disheight);

	for (int idy = 0; idy < disheight; idy++) {
		for (int idx=0; idx < diswidth ; idx++) {
			g_FrameBuffer[2 * (idy+xstart) * lcddev.width + (idx+ystart*2)] = image.ptrArr[ 2 * idy * image.height + idx];//0xFFFF;
			//osal_printk("posx: %d, posy: %d, byteidx: %d\r\n",idx, idy, 2 * idx * LCD_W + idy);
		}
	}


	
	// for (int idx = 0; idx < image.width; idx++) {
	// 	for (int idy=0; idy < image.height*2 ; idy++) {
	// 		g_FrameBuffer[2 * (idx+xstart) * lcddev.width + (idy+ystart*2)] = image.ptrArr[ 2 * idx * image.height + idy];//0xFFFF;
	// 		//osal_printk("posx: %d, posy: %d, byteidx: %d\r\n",idx, idy, 2 * idx * LCD_W + idy);
	// 	}
	// }
	
	LCDOutputAFrameU8(g_FrameBuffer);
}




